package com.aiwu;

import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;

import androidx.annotation.Nullable;

import com.aiwu.library.AiwuSimulator;
import com.aiwu.library.HandleMapManager;
import com.aiwu.library.bean.Action;
import com.aiwu.library.bean.ClickOperateButtonBean;
import com.aiwu.library.bean.Direction;
import com.aiwu.library.bean.OneKeyOperate;
import com.aiwu.library.util.ThreadPoolManager;

import org.citra.citra_emu.NativeLibrary;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * 输入管理
 */
public class InputManager {
    public static final String KEY_A = "A";
    public static final String KEY_B = "B";
    public static final String KEY_X = "X";
    public static final String KEY_Y = "Y";
    public static final String KEY_L = "L";
    public static final String KEY_R = "R";
    public static final String KEY_ZL = "ZL";
    public static final String KEY_ZR = "ZR";
    public static final String KEY_SELECT = "SELECT";
    public static final String KEY_START = "START";
    public static final String KEY_ROCKER_CROSS = "ROCKER_CROSS";
    public static final String KEY_ROCKER_MAIN = "ROCKER_MAIN";
    public static final String KEY_ROCKER_C = "ROCKER_C";

    private final HashMap<String, Integer> mBtnMap = new HashMap<>();
    private final HashMap<String, Integer[]> mDirectionMap = new HashMap<>();
    private final HashSet<Integer> mBtnEventSet = new HashSet<>();
    private final HashSet<Integer> mMotionEventSet = new HashSet<>();

    private int mTouchscreenPointerId = -1;
    private List<Integer> mLastCodes;
    //一键大招释放中
    private boolean mOneKeying;

    public InputManager() {
        resetValue();
    }

    private void resetValue() {
        mBtnMap.clear();
        mBtnMap.put(KEY_L, NativeLibrary.ButtonType.TRIGGER_L);
        mBtnMap.put(KEY_R, NativeLibrary.ButtonType.TRIGGER_R);
        mBtnMap.put(KEY_ZL, NativeLibrary.ButtonType.BUTTON_ZL);
        mBtnMap.put(KEY_ZR, NativeLibrary.ButtonType.BUTTON_ZR);
        mBtnMap.put(KEY_A, NativeLibrary.ButtonType.BUTTON_A);
        mBtnMap.put(KEY_B, NativeLibrary.ButtonType.BUTTON_B);
        mBtnMap.put(KEY_X, NativeLibrary.ButtonType.BUTTON_X);
        mBtnMap.put(KEY_Y, NativeLibrary.ButtonType.BUTTON_Y);
        mBtnMap.put(KEY_SELECT, NativeLibrary.ButtonType.BUTTON_SELECT);
        mBtnMap.put(KEY_START, NativeLibrary.ButtonType.BUTTON_START);

        mDirectionMap.clear();
        mDirectionMap.put(Direction.DIRECTION_UP.name(), new Integer[]{NativeLibrary.ButtonType.DPAD_UP});
        mDirectionMap.put(Direction.DIRECTION_UP_RIGHT.name(), new Integer[]{NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonType.DPAD_RIGHT});
        mDirectionMap.put(Direction.DIRECTION_RIGHT.name(), new Integer[]{NativeLibrary.ButtonType.DPAD_RIGHT});
        mDirectionMap.put(Direction.DIRECTION_DOWN_RIGHT.name(), new Integer[]{NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonType.DPAD_RIGHT});
        mDirectionMap.put(Direction.DIRECTION_DOWN.name(), new Integer[]{NativeLibrary.ButtonType.DPAD_DOWN});
        mDirectionMap.put(Direction.DIRECTION_DOWN_LEFT.name(), new Integer[]{NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonType.DPAD_LEFT});
        mDirectionMap.put(Direction.DIRECTION_LEFT.name(), new Integer[]{NativeLibrary.ButtonType.DPAD_LEFT});
        mDirectionMap.put(Direction.DIRECTION_UP_LEFT.name(), new Integer[]{NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonType.DPAD_LEFT});

        mBtnEventSet.clear();
        mBtnEventSet.add(NativeLibrary.ButtonType.BUTTON_A);
        mBtnEventSet.add(NativeLibrary.ButtonType.BUTTON_B);
        mBtnEventSet.add(NativeLibrary.ButtonType.BUTTON_X);
        mBtnEventSet.add(NativeLibrary.ButtonType.BUTTON_Y);
        mBtnEventSet.add(NativeLibrary.ButtonType.BUTTON_SELECT);
        mBtnEventSet.add(NativeLibrary.ButtonType.BUTTON_START);
        mBtnEventSet.add(NativeLibrary.ButtonType.TRIGGER_L);
        mBtnEventSet.add(NativeLibrary.ButtonType.TRIGGER_R);
        mBtnEventSet.add(NativeLibrary.ButtonType.BUTTON_ZL);
        mBtnEventSet.add(NativeLibrary.ButtonType.BUTTON_ZR);
        mBtnEventSet.add(NativeLibrary.ButtonType.DPAD_UP);
        mBtnEventSet.add(NativeLibrary.ButtonType.DPAD_DOWN);
        mBtnEventSet.add(NativeLibrary.ButtonType.DPAD_LEFT);
        mBtnEventSet.add(NativeLibrary.ButtonType.DPAD_RIGHT);
        mBtnEventSet.add(HandleMapManager.VALUE_SAVE_FAST_ARCHIVE);
        mBtnEventSet.add(HandleMapManager.VALUE_LOAD_FAST_ARCHIVE);

        mMotionEventSet.clear();
        mMotionEventSet.add(NativeLibrary.ButtonType.STICK_LEFT_UP);
        mMotionEventSet.add(NativeLibrary.ButtonType.STICK_LEFT_DOWN);
        mMotionEventSet.add(NativeLibrary.ButtonType.STICK_LEFT_LEFT);
        mMotionEventSet.add(NativeLibrary.ButtonType.STICK_LEFT_RIGHT);
        mMotionEventSet.add(NativeLibrary.ButtonType.STICK_C_UP);
        mMotionEventSet.add(NativeLibrary.ButtonType.STICK_C_DOWN);
        mMotionEventSet.add(NativeLibrary.ButtonType.STICK_C_LEFT);
        mMotionEventSet.add(NativeLibrary.ButtonType.STICK_C_RIGHT);
    }

    @Nullable
    public List<Integer> getDirectionKeyCodes(String key) {
        Integer[] array = mDirectionMap.get(key);
        if (array != null) {
            return Arrays.asList(array);
        }
        return null;
    }

    public Integer getKeyCode(String key) {
        return mBtnMap.get(key);
    }

    public List<Integer> getKeyCodes(ClickOperateButtonBean... clickOperateButtonBeans) {
        List<Integer> keyCodes = new ArrayList<>();
        for (ClickOperateButtonBean bean : clickOperateButtonBeans) {
            Integer keyCode = getKeyCode(bean.getId());
            keyCodes.add(keyCode);
        }
        return keyCodes;
    }

    /**
     * 按键按下
     *
     * @param burst
     * @param buttons
     */
    public void onButtonClick(boolean burst, ClickOperateButtonBean[] buttons) {
        ThreadPoolManager.getInstance().executeTask(() -> {
            List<Integer> keyCodes = getKeyCodes(buttons);
            if (burst) {
                if (mLastCodes != null) {
                    postKeyCodeEvent(false, mLastCodes);
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                postKeyCodeEvent(true, keyCodes);
                mLastCodes = keyCodes;
            } else {
                postKeyCodeEvent(true, keyCodes);
            }
        });
    }

    /**
     * 按键抬起
     *
     * @param burst
     * @param buttons
     */
    public void onButtonRelease(boolean burst, ClickOperateButtonBean[] buttons) {
        ThreadPoolManager.getInstance().executeTask(() -> {
            if (burst) {
                mLastCodes = null;
            }
            List<Integer> keyCodes = getKeyCodes(buttons);
            postKeyCodeEvent(false, keyCodes);
        });
    }

    /**
     * 一键大招
     *
     * @param advancedMode
     * @param buttons
     */
    public void onOneKeyClick(boolean advancedMode, List<OneKeyOperate> buttons) {
        if (mOneKeying) {
            return;
        }
        ThreadPoolManager.getInstance().executeTask(() -> {
            mOneKeying = true;
            if (advancedMode) {//高级
                for (int i = 0; i < buttons.size(); i++) {
                    OneKeyOperate operate = buttons.get(i);
                    switch (operate.getAction()) {
                        case SEND:
                            //该模拟器没有发送的说法,所有也不需要补全最后一个发送
                            //最后一个发送操作不需要延迟了
                            if (i != buttons.size() - 1) {
                                try {
                                    Thread.sleep(150);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            break;
                        case DOWN:
                            postOneKeyEvent(true, operate.getKeyId());
                            break;
                        case UP:
                            postOneKeyEvent(false, operate.getKeyId());
                            break;
                        default:
                            break;
                    }
                }
            } else {
                for (int i = 0; i < buttons.size(); i++) {
                    OneKeyOperate operate = buttons.get(i);
                    if (operate.getAction() != Action.DOWN) {//过滤无用操作
                        continue;
                    }
                    postOneKeyEvent(true, operate.getKeyId());
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    postOneKeyEvent(false, operate.getKeyId());
                    if (i != buttons.size() - 1) {
                        try {
                            Thread.sleep(150);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            mOneKeying = false;
        });
    }

    /**
     * 发送一键大招事件
     *
     * @param down
     * @param key
     */
    private void postOneKeyEvent(boolean down, String key) {
        Integer btnKeyCode = getKeyCode(key);
        if (btnKeyCode != null) {//按钮
            postKeyCodeEvent(down, btnKeyCode);
        } else {//可能是方向
            List<Integer> directionKeyCodes = getDirectionKeyCodes(key);
            if (directionKeyCodes != null) {
                postKeyCodeEvent(down, directionKeyCodes);
            }
        }
    }

    private void postKeyCodeEvent(boolean down, Integer keyCode) {
        if (keyCode == null) {
            return;
        }
        NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, keyCode, down ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED);
    }

    private void postKeyCodeEvent(boolean down, List<Integer> keyCodes) {
        for (Integer code : keyCodes) {
            if (code == null) {
                continue;
            }
            NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, code, down ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED);
        }
    }

    public void resetAxises(boolean mainRocker) {
        int axisID = mainRocker ? NativeLibrary.ButtonType.STICK_LEFT : NativeLibrary.ButtonType.STICK_C;
        NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, axisID, 0f, 0f);
    }

    /**
     * 摇杆
     *
     * @param xAxisesRatio
     * @param yAxisesRatio
     * @param mainRocker   是否主摇杆
     */
    public void onAxisesChanged(float xAxisesRatio, float yAxisesRatio, boolean mainRocker) {
        int axisID = mainRocker ? NativeLibrary.ButtonType.STICK_LEFT : NativeLibrary.ButtonType.STICK_C;
        NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, axisID, xAxisesRatio, yAxisesRatio);
    }

    public void resetDirection() {
        NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.RELEASED);
        NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.RELEASED);
        NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.RELEASED);
        NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.RELEASED);
    }

    /**
     * 十字键
     *
     * @param direction
     */
    public void onDirectionChanged(Direction direction) {
        switch (direction) {
            case DIRECTION_UP:
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.RELEASED);
                break;
            case DIRECTION_UP_RIGHT:
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.RELEASED);
                break;
            case DIRECTION_RIGHT:
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.RELEASED);
                break;
            case DIRECTION_DOWN_RIGHT:
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.RELEASED);
                break;
            case DIRECTION_DOWN:
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.RELEASED);
                break;
            case DIRECTION_DOWN_LEFT:
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.RELEASED);
                break;
            case DIRECTION_LEFT:
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.RELEASED);
                break;
            case DIRECTION_UP_LEFT:
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.PRESSED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.RELEASED);
                NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.RELEASED);
                break;
        }
    }

    /**
     * 触摸屏幕
     *
     * @param event
     */
    public void onTouchEvent(MotionEvent event) {
        int pointerIndex = event.getActionIndex();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_POINTER_DOWN:
                if (NativeLibrary.onTouchEvent(event.getX(pointerIndex), event.getY(pointerIndex), true)) {
                    mTouchscreenPointerId = event.getPointerId(pointerIndex);
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                if (mTouchscreenPointerId == event.getPointerId(pointerIndex)) {
                    // We don't really care where the touch has been released. We only care whether it has been
                    // released or not.
                    NativeLibrary.onTouchEvent(0, 0, false);
                    mTouchscreenPointerId = -1;
                }
                break;
        }

        for (int i = 0; i < event.getPointerCount(); i++) {
            if (mTouchscreenPointerId == event.getPointerId(i)) {
                NativeLibrary.onTouchMoved(event.getX(i), event.getY(i));
            }
        }
    }

    /**
     * 按键事件
     */
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getRepeatCount() != 0) {
            return false;
        }
        if (event.getAction() != KeyEvent.ACTION_DOWN && event.getAction() != KeyEvent.ACTION_UP) {
            return false;
        }
        InputDevice input = event.getDevice();
        if (input == null) {
            return false;
        }
        String deviceDescriptor = input.getDescriptor();
        int[] mappedKeyCode = AiwuSimulator.keyMapping(deviceDescriptor, event.getKeyCode(), event.getAction());
        if (mappedKeyCode == null) {
            return false;
        }
        //        int player = mappedKeyCode[0];
        int code = mappedKeyCode[1];
        if (AiwuSimulator.isInternalKeyCode(code)) {
            //内部已经处理
            return true;
        }
        return handleEvent(deviceDescriptor, code, event.getAction(), true);
    }

    /**
     * 轴事件
     */
    public boolean dispatchGenericMotionEvent(MotionEvent event) {
        final int source = event.getSource();
        if ((source & InputDevice.SOURCE_JOYSTICK) == 0)
            return false;
        if (event.getActionMasked() == MotionEvent.ACTION_CANCEL)
            return true;
        InputDevice input = event.getDevice();
        if (input == null) {
            return false;
        }
        String deviceDescriptor = input.getDescriptor();
        List<InputDevice.MotionRange> motions = input.getMotionRanges();
        for (InputDevice.MotionRange range : motions) {
            int axis = range.getAxis();
            float origValue = event.getAxisValue(axis);
            int[] mappedKeyCode = AiwuSimulator.MotionMapping(deviceDescriptor, axis, origValue);
            if (mappedKeyCode == null) {
                //没映射过的运动事件，跳过
                continue;
            }
//            int player = mappedKeyCode[0];
            int code1 = mappedKeyCode[1];
            handleMotionCode(input, range, deviceDescriptor, code1, axis, origValue);
            if (mappedKeyCode.length > 2) {
                int code2 = mappedKeyCode[2];
                handleMotionCode(input, range, deviceDescriptor, code2, axis, origValue);
            }
        }
        return true;
    }

    private void handleMotionCode(InputDevice input, InputDevice.MotionRange range, String deviceDescriptor, int code, int axis, float origValue) {
        if (AiwuSimulator.isInternalKeyCode(code)) {
            //内部已经处理，跳过
            return;
        }
        float value = HandleMapManager.scaleAxis(input, axis, origValue);
        value = Math.abs(value) <= range.getFlat() ? 0.0f : value;
        handleEvent(deviceDescriptor, code, value, false);
    }

    private boolean handleEvent(String deviceDescriptor, int code, float value, boolean isKeyEvent) {
        boolean isActionDown = isKeyEvent ? value == KeyEvent.ACTION_DOWN : value != 0.0f;
        if (handleButtonEvent(deviceDescriptor, code, isActionDown)) {
            return true;
        }
        float motionValue = isKeyEvent ? (value == KeyEvent.ACTION_DOWN ? 1.0f : 0.0f) : value;
        if (handleMotionEvent(deviceDescriptor, code, motionValue)) {
            return true;
        }
        return false;
    }

    private boolean handleButtonEvent(String deviceDescriptor, int code, boolean actionDown) {
        if (mBtnEventSet.contains(code)) {
            switch (code) {
                case HandleMapManager.VALUE_SAVE_FAST_ARCHIVE:
                    if (actionDown) {
                        ArchiveManger.getInstance().saveFastArchive();
                    }
                    break;
                case HandleMapManager.VALUE_LOAD_FAST_ARCHIVE:
                    if (actionDown) {
                        ArchiveManger.getInstance().loadFastArchive();
                    }
                    break;
                case NativeLibrary.ButtonType.DPAD_UP:
                    NativeLibrary.onGamePadEvent(deviceDescriptor, NativeLibrary.ButtonType.DPAD_UP, actionDown ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED);
                    NativeLibrary.onGamePadEvent(deviceDescriptor, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.RELEASED);
                    break;
                case NativeLibrary.ButtonType.DPAD_DOWN:
                    NativeLibrary.onGamePadEvent(deviceDescriptor, NativeLibrary.ButtonType.DPAD_DOWN, actionDown ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED);
                    NativeLibrary.onGamePadEvent(deviceDescriptor, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.RELEASED);
                    break;
                case NativeLibrary.ButtonType.DPAD_LEFT:
                    NativeLibrary.onGamePadEvent(deviceDescriptor, NativeLibrary.ButtonType.DPAD_LEFT, actionDown ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED);
                    NativeLibrary.onGamePadEvent(deviceDescriptor, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.RELEASED);
                    break;
                case NativeLibrary.ButtonType.DPAD_RIGHT:
                    NativeLibrary.onGamePadEvent(deviceDescriptor, NativeLibrary.ButtonType.DPAD_RIGHT, actionDown ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED);
                    NativeLibrary.onGamePadEvent(deviceDescriptor, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.RELEASED);
                    break;
                default:
                    NativeLibrary.onGamePadEvent(deviceDescriptor, code, actionDown ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED);
                    break;
            }
            return true;
        }
        return false;
    }

    private boolean handleMotionEvent(String deviceDescriptor, int code, float value) {
        if (mMotionEventSet.contains(code)) {
            switch (code) {
                case NativeLibrary.ButtonType.STICK_LEFT_UP:
                case NativeLibrary.ButtonType.STICK_LEFT_DOWN:
                    NativeLibrary.AiWuOnGamePadMoveEvent(deviceDescriptor, NativeLibrary.ButtonType.STICK_LEFT, value, false);
                    break;
                case NativeLibrary.ButtonType.STICK_LEFT_LEFT:
                case NativeLibrary.ButtonType.STICK_LEFT_RIGHT:
                    NativeLibrary.AiWuOnGamePadMoveEvent(deviceDescriptor, NativeLibrary.ButtonType.STICK_LEFT, value, true);
                    break;
                case NativeLibrary.ButtonType.STICK_C_UP:
                case NativeLibrary.ButtonType.STICK_C_DOWN:
                    NativeLibrary.AiWuOnGamePadMoveEvent(deviceDescriptor, NativeLibrary.ButtonType.STICK_C, value, false);
                    break;
                case NativeLibrary.ButtonType.STICK_C_LEFT:
                case NativeLibrary.ButtonType.STICK_C_RIGHT:
                    NativeLibrary.AiWuOnGamePadMoveEvent(deviceDescriptor, NativeLibrary.ButtonType.STICK_C, value, true);
                    break;
                default:
                    break;
            }
            return true;
        }
        return false;
    }

    public static int[] getHandleMapValues() {
        return new int[]{
                NativeLibrary.ButtonType.BUTTON_A,
                NativeLibrary.ButtonType.BUTTON_B,
                NativeLibrary.ButtonType.BUTTON_X,
                NativeLibrary.ButtonType.BUTTON_Y,

                NativeLibrary.ButtonType.TRIGGER_L,
                NativeLibrary.ButtonType.TRIGGER_R,
                NativeLibrary.ButtonType.BUTTON_ZL,
                NativeLibrary.ButtonType.BUTTON_ZR,

                NativeLibrary.ButtonType.BUTTON_SELECT,
                NativeLibrary.ButtonType.BUTTON_START,

                HandleMapManager.VALUE_F1,
                HandleMapManager.VALUE_F2,
                HandleMapManager.VALUE_F3,
                HandleMapManager.VALUE_F4,

                HandleMapManager.VALUE_C1,
                HandleMapManager.VALUE_C2,
                HandleMapManager.VALUE_C3,
                HandleMapManager.VALUE_C4,

                HandleMapManager.VALUE_SAVE_FAST_ARCHIVE,
                HandleMapManager.VALUE_LOAD_FAST_ARCHIVE,

                NativeLibrary.ButtonType.DPAD_UP,
                NativeLibrary.ButtonType.DPAD_DOWN,
                NativeLibrary.ButtonType.DPAD_LEFT,
                NativeLibrary.ButtonType.DPAD_RIGHT,

                NativeLibrary.ButtonType.STICK_LEFT_UP,
                NativeLibrary.ButtonType.STICK_LEFT_DOWN,
                NativeLibrary.ButtonType.STICK_LEFT_LEFT,
                NativeLibrary.ButtonType.STICK_LEFT_RIGHT,

                NativeLibrary.ButtonType.STICK_C_UP,
                NativeLibrary.ButtonType.STICK_C_DOWN,
                NativeLibrary.ButtonType.STICK_C_LEFT,
                NativeLibrary.ButtonType.STICK_C_RIGHT,
        };
    }

    public static String[] getHandleMapNames() {
        return new String[]{
                "A", "B", "X", "Y",
                "L", "R", "ZL", "ZR",
                "START", "SELECT",
                "F1", "F2", "F3", "F4",
                "C1", "C2", "C3", "C4",
                "快速存档", "快速读档",
                "方向键 ↑", "方向键 ↓", "方向键 ←", "方向键 →",
                "主摇杆 ↑", "主摇杆 ↓", "主摇杆 ←", "主摇杆 →",
                "C摇杆 ↑", "C摇杆 ↓", "C摇杆 ←", "C摇杆 →"
        };
    }

    public static HashMap<String, Integer> getDefaultHandleMap() {
        HashMap<String, Integer> keyMap = new HashMap<>();
        keyMap.put(KeyEvent.KEYCODE_BUTTON_START + "", NativeLibrary.ButtonType.BUTTON_START);
        keyMap.put(KeyEvent.KEYCODE_BUTTON_SELECT + "", NativeLibrary.ButtonType.BUTTON_SELECT);
        keyMap.put(KeyEvent.KEYCODE_BUTTON_B + "", NativeLibrary.ButtonType.BUTTON_B);
        keyMap.put(KeyEvent.KEYCODE_BUTTON_Y + "", NativeLibrary.ButtonType.BUTTON_Y);
        keyMap.put(KeyEvent.KEYCODE_BUTTON_A + "", NativeLibrary.ButtonType.BUTTON_A);
        keyMap.put(KeyEvent.KEYCODE_BUTTON_X + "", NativeLibrary.ButtonType.BUTTON_X);
        keyMap.put(KeyEvent.KEYCODE_BUTTON_L1 + "", NativeLibrary.ButtonType.TRIGGER_L);
        keyMap.put(KeyEvent.KEYCODE_BUTTON_R1 + "", NativeLibrary.ButtonType.TRIGGER_R);
        keyMap.put(KeyEvent.KEYCODE_BUTTON_L2 + "", NativeLibrary.ButtonType.BUTTON_ZL);
        keyMap.put(KeyEvent.KEYCODE_BUTTON_R2 + "", NativeLibrary.ButtonType.BUTTON_ZR);

        keyMap.put(MotionEvent.AXIS_HAT_Y + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE, NativeLibrary.ButtonType.DPAD_UP);
        keyMap.put(MotionEvent.AXIS_HAT_Y + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE, NativeLibrary.ButtonType.DPAD_DOWN);
        keyMap.put(MotionEvent.AXIS_HAT_X + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE, NativeLibrary.ButtonType.DPAD_LEFT);
        keyMap.put(MotionEvent.AXIS_HAT_X + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE, NativeLibrary.ButtonType.DPAD_RIGHT);

        keyMap.put(MotionEvent.AXIS_Y + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE, NativeLibrary.ButtonType.STICK_LEFT_UP);
        keyMap.put(MotionEvent.AXIS_Y + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE, NativeLibrary.ButtonType.STICK_LEFT_DOWN);
        keyMap.put(MotionEvent.AXIS_X + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE, NativeLibrary.ButtonType.STICK_LEFT_LEFT);
        keyMap.put(MotionEvent.AXIS_X + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE, NativeLibrary.ButtonType.STICK_LEFT_RIGHT);

        keyMap.put(MotionEvent.AXIS_RZ + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE, NativeLibrary.ButtonType.STICK_C_UP);
        keyMap.put(MotionEvent.AXIS_RZ + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE, NativeLibrary.ButtonType.STICK_C_DOWN);
        keyMap.put(MotionEvent.AXIS_Z + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE, NativeLibrary.ButtonType.STICK_C_LEFT);
        keyMap.put(MotionEvent.AXIS_Z + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE, NativeLibrary.ButtonType.STICK_C_RIGHT);
        return keyMap;
    }
}
